package com.ym.pms.security.filter;


import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.ym.pms.config.Constants;
import com.ym.pms.security.config.JWTConfig;
import com.ym.pms.security.entity.SysUserDetails;
import com.ym.pms.utils.AccessAddressUtils;
import com.ym.pms.utils.JSONResult;
import com.ym.pms.security.utils.JWTTokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;


import lombok.extern.slf4j.Slf4j;

/**
 * @Author: xybh
 * @Description:
 * @Date: Created in 11:11 2020/12/21
 * @Modified:
 */
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        // 取出Token
        String token = request.getHeader(JWTConfig.tokenHeader);

        if (!StringUtils.isBlank(token)&& token.startsWith(JWTConfig.tokenPrefix)) {
            // 是否在黑名单中
            if (JWTTokenUtil.isBlackList(token)) {
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json");
                response.getWriter().println(JSON.toJSONString(JSONResult.build(505, "Token已失效", "Token已进入黑名单")));
                return;
            }

            // 是否存在于Redis中
            if (JWTTokenUtil.hasToken(token)) {
                String ip = AccessAddressUtils.getIpAddress(request);
                String expiration = JWTTokenUtil.getExpirationByToken(token);
                String username = JWTTokenUtil.getUserNameByToken(token);

                // 判断是否过期
                if (JWTTokenUtil.isExpiration(expiration)) {
                    // 加入黑名单
                    JWTTokenUtil.addBlackList(token);

                    // 是否在刷新期内
                    String validTime = JWTTokenUtil.getRefreshTimeByToken(token);
                    if (JWTTokenUtil.isValid(validTime)) {
                        // 刷新Token，重新存入请求头
                        String newToke = JWTTokenUtil.refreshAccessToken(token);

                        // 删除旧的Token，并保存新的Token
                        JWTTokenUtil.deleteRedisToken(token);
                        JWTTokenUtil.setTokenInfo(newToke, username, ip);
                        response.setHeader(JWTConfig.tokenHeader, newToke);

                        log.info("用户{}的Token已过期，但未超过刷新时间，已刷新", username);

                        token = newToke;
                    } else {

                        log.info("用户{}的Token已过期且超过刷新时间，不予刷新", username);

                        // 加入黑名单
                        JWTTokenUtil.addBlackList(token);
                        response.setCharacterEncoding("UTF-8");
                        response.setContentType("application/json");
                        response.getWriter().println(JSON.toJSONString(JSONResult.build(505, "Token已过期", "已超过刷新有效期")));
                        return;
                    }
                }

                SysUserDetails sysUserDetails = JWTTokenUtil.parseAccessToken(token);

                if (sysUserDetails != null) {
//                    // 校验IP
//                    if (!StringUtils.equals(ip, sysUserDetails.getIp())) {
//
//                        log.info("用户{}请求IP与Token中IP信息不一致", username);
//
//                        // 加入黑名单
//                        JWTTokenUtil.addBlackList(token);
//                        response.setCharacterEncoding("UTF-8");
//                        response.setContentType("application/json");
//                        response.getWriter().println(JSON.toJSONString(JSONResult.build(505, "Token已过期", "可能存在IP伪造风险")));
//                        return;
//                    }

                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                            sysUserDetails, sysUserDetails.getUId(), sysUserDetails.getAuthorities());
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        request.setAttribute(Constants.CURRENT_USER_ID, token);
        filterChain.doFilter(request, response);
    }

}